import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

import java.awt.image.BufferStrategy;

import java.util.ArrayList;
import java.util.Collections;


public final class RenderEngine implements Runnable
{
	//vars needed for bassline rendering
	boolean isRunning;
	double other;
	Canvas gui;
	long cycleTime;
	double FrameLimit = game.framelimit;
	long lastTime = System.nanoTime();
	double unprocessedSeconds = 0;
	double secondsPerTick = 1 / FrameLimit;
	boolean ticked = false;
	int tickCount;
	int frames;
	//VARIABLES FOR BAD RENDERING
	//function vars
	static boolean paused;
	static ArrayList<Sprite> spritelist = new ArrayList<Sprite>();
	static ArrayList<Thread> thredlist = new ArrayList<Thread>();
	static int globalXorigin = 0;
	static int globalYorigin = 0;
	
	public RenderEngine(Canvas canvas) 
	{
		//on start
		paused = true;
		gui = canvas;
		isRunning = true;
		//let game rn it's init func
		game.onstart();
	}
	public void run() 
	{
		BufferStrategy strategy = null;

			cycleTime = System.currentTimeMillis();
			gui.createBufferStrategy(2);
			strategy = gui.getBufferStrategy();
		// Game Loop
		/*while (isRunning) 
		{
			Main.timekeeperreset();
			Main.timekeeper("game.onupdate");
			//update game
			game.onupdate();
			Main.timekeeper("game updated, updateGUI");
			//update locals
			//render
			updateGUI(strategy);
			Main.timekeeper("rendered - synchFramerate");
			synchFramerate();
			Main.timekeeper("finished");
			//Main.timekeeperdisplay();
		} */
		while (isRunning) 
		{
			Main.timekeeperreset();
			Main.timekeeper("Legacy Runthread started");
			//check if we still have focus
			/*if (!canvas.hasFocus() && game.forcefocus){
				paused = true;
			}*/
			long now = System.nanoTime();
			long passedTime = now - lastTime;
			lastTime = now;
			if (passedTime < 0) passedTime = 0;
			if (passedTime > 100000000) passedTime = 100000000;

			unprocessedSeconds += passedTime / 1000000000.0;

			boolean ticked = false;
			while (unprocessedSeconds > secondsPerTick) {
				//Main.logic.update();
				unprocessedSeconds -= secondsPerTick;
				ticked = true;
				tickCount++;
				if (tickCount % FrameLimit == 0) 
				{
					if(game.showfps)
						{
						System.out.println(frames + " fps");
						}
					lastTime += 1000;
					frames = 0;
				}
			}
			if (ticked) 
			{
				updatesprites();
				Main.timekeeper("sprites updated");
				game.onupdate();
				Main.timekeeper("game updated");
				updateGUI(strategy);
				Main.timekeeper("rendered");
				frames++;
			} else {
				try 
				{
					Thread.sleep(1);
				} catch (InterruptedException e) 
				{
					e.printStackTrace();
				}
			}
		}
	}
	private void updatesprites(){
		for(int i=0;i<spritelist.size();i++)
    	{
    		if (spritelist.get(i) != null)
    		{
    			Runnable task = spritelist.get(i);
    			Thread worker = new Thread(task);
    			worker.start();
    			//worker.setPriority(Thread.MAX_PRIORITY); //hold onto yer butts
    			thredlist.add(worker);
    		}
    	}
		//wait for all the threads to finish
		for(int i=0;i<thredlist.size();) // need to make this a while loop as some threads can escape
    	{
    		if (!thredlist.get(i).isAlive())
    		{
    			thredlist.remove(i);
    			i++;
    		}
    	}
	}
	private void updateGUI(BufferStrategy strategy) {
		Graphics g = null;
		//start the process thread of all the sprites
			 g = strategy.getDrawGraphics();

		Main.timekeeper("all sprite threads finished updates");
		//tonight we render in hell
		//graphics = null;
		if (!paused){
			for(int i=0;i<spritelist.size();i++)
			{
				if (spritelist.get(i) != null)
				{
					//get some attributes
					if(spritelist.get(i).rot != 0)
					//if(1==2)
					{
						g.translate((int)(spritelist.get(i).x+spritelist.get(i).Xoffset+globalXorigin), (int)(spritelist.get(i).y+spritelist.get(i).Yoffset+globalYorigin));
						//g.rotate(spritelist.get(i).rot);
						if (spritelist.get(i).Type == ""){
							g.drawImage(Main.SpriteStore.getSprite(spritelist.get(i).picture1), 0, 0,null);
						}else{
							//it's a geosprite
							g.setColor(spritelist.get(i).Col); //get the colour
							if (spritelist.get(i).Type == "rect"){
								//and it's a rectangle
								g.fillRect((int)spritelist.get(i).x+globalXorigin,(int)spritelist.get(i).y, spritelist.get(i).Width, spritelist.get(i).Height); 
							}else if(spritelist.get(i).Type == "text"){
								//it's text
								g.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
								g.setColor( Color.GREEN );
								g.drawString(spritelist.get(i).text, (int)spritelist.get(i).x, (int)spritelist.get(i).y );
							}else{
								// it's somthing else that hasn't been coded yet
							}
						}
						//g.rotate(-spritelist.get(i).rot);
						g.translate(-(int)(spritelist.get(i).x+spritelist.get(i).Xoffset+globalXorigin), -(int)(spritelist.get(i).y+spritelist.get(i).Yoffset+globalYorigin));
					}else{
						if (spritelist.get(i).Type == "image"){
							g.drawImage(Main.SpriteStore.getSprite(spritelist.get(i).picture1), (int)(spritelist.get(i).x+spritelist.get(i).Xoffset+globalXorigin), (int)(spritelist.get(i).y+spritelist.get(i).Yoffset+globalYorigin),null);
						}else{
							//it's a geosprite
							g.setColor(spritelist.get(i).Col); //get the colour
							if (spritelist.get(i).Type == "rect"){
								//and it's a rectangle
								g.fillRect((int)spritelist.get(i).x+globalXorigin,(int)spritelist.get(i).y, spritelist.get(i).Width, spritelist.get(i).Height);  
							}else if(spritelist.get(i).Type == "text"){
								//it's text
								g.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
								g.setColor( Color.GREEN );
								g.drawString(spritelist.get(i).text,(int)Math.round(spritelist.get(i).x),(int)Math.round(spritelist.get(i).y));
							}else{
								// it's somthing else that hasn't been coded yet
							}
						}
					}
				}
			}
		}else{
			g.setColor(Color.black);
			g.fillRect( 0, 0, 1100, 500);
			g.setColor(Color.green);
			g.drawString(game.gamename, 200, 200);
			if(game.showmenupicture){
				g.drawImage(Main.SpriteStore.getSprite(game.menupicture), 0,0,null);
			}
			g.drawString("press ESC to begin", 300, 400);
		}
		Main.timekeeper("Everything has been drawn");
		g.dispose();
		strategy.show();
		Main.timekeeper("buffers have been blitted");
	}
	 
	private void synchFramerate() {
		cycleTime = cycleTime + Main.FRAME_DELAY;
		long difference = cycleTime - System.currentTimeMillis();
		try
		{
			Thread.sleep(Math.max(0, difference));
		}
		catch(InterruptedException e) 
		{
			e.printStackTrace();
		}
		
	}
	static void addsprite(Sprite spritetobeadded)
	{
		spritelist.add(spritetobeadded);
		// --------MOST IMPORTANT LINE IN THE JOINT ---
		Collections.sort(spritelist);
		// ------------MEET THE Z-BUFFER WIZARD!-------

	}
	static void removeSprite(Sprite spritetoberemoved)
	{
		spritelist.remove(spritetoberemoved);
		Collections.sort(spritelist);
	}
}
